package net.sudot.chess.business.dao;

import net.sudot.chess.business.dto.PaymentItemDTO;
import net.sudot.chess.business.model.PaymentTransaction;
import net.sudot.chess.plugin.payment.PaymentPlugin;
import org.springframework.stereotype.Repository;

import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.math.BigDecimal;
import java.time.Instant;

/**
 * 支付事务
 *
 * @author tangjialin on 2018-03-20.
 */
@Repository
public class PaymentTransactionDao extends BaseDao<PaymentTransaction> {

    /**
     * 查找可用支付事务
     *
     * @param itemDTO       支付项
     *                      itemDTO.type    :(必需)支付类型
     *                      itemDTO.orderSn :(必需)订单编号
     *                      itemDTO.amount  :(必需)支付金额
     *                      itemDTO.userId  :(必需)支付用户
     *                      itemDTO.target  :(必需)支付对象
     * @param paymentPlugin 支付插件
     * @return 可用支付事务，若不存在则返回null
     */
    public PaymentTransaction findAvailable(PaymentItemDTO itemDTO, PaymentPlugin paymentPlugin) {
        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
        CriteriaQuery<PaymentTransaction> criteriaQuery = criteriaBuilder.createQuery(PaymentTransaction.class);
        Root<PaymentTransaction> root = criteriaQuery.from(PaymentTransaction.class);
        criteriaQuery.select(root);
        BigDecimal amount = paymentPlugin.calculateAmount(itemDTO.getAmount());
        Predicate restrictions = criteriaBuilder.and(criteriaBuilder.conjunction(),
                criteriaBuilder.equal(root.get("userId"), itemDTO.getUserId()),
                criteriaBuilder.equal(root.get("type"), itemDTO.getType()),
                criteriaBuilder.equal(root.get("amount"), amount),
                criteriaBuilder.equal(root.get("success"), false),
                criteriaBuilder.equal(root.get("paymentPluginId"), paymentPlugin.getId()),
                criteriaBuilder.greaterThan(root.get("expire"), Instant.now()),
                criteriaBuilder.equal(root.get("target"), itemDTO.getTarget())
        );
        return uniqueResult(entityManager.createQuery(criteriaQuery.where(restrictions)));
    }

    /**
     * 获取支付事务
     *
     * @param type   类型
     * @param target 支付对象
     * @return 返回支付事务
     */
    public PaymentTransaction findByTarget(PaymentTransaction.Type type, Long target) {
        String ql = "SELECT paymentTransaction FROM PaymentTransaction paymentTransaction WHERE paymentTransaction.type = :type AND paymentTransaction.target = :target";
        TypedQuery<PaymentTransaction> query = entityManager.createQuery(ql, PaymentTransaction.class);
        query.setParameter("type", type);
        query.setParameter("target", target);
        return uniqueResult(query);
    }
}